`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/19 20:12:04
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


/* UART receive */

module uart_rx(
    input clk,
    input rst,
    input rx,

    output reg [7:0] rx_data,
    output reg rx_done
    );

    parameter CLK_F = 100000000;
    parameter UART_B = 9600;
    parameter B_CNT = CLK_F / UART_B;

    reg rxd_en;
    reg [1:0] rx_r1;
    reg [1:0] rx_r2;
    reg [15:0] baud_cnt = 16'd0;
    reg [3:0] bit_cnt = 4'd0;
    reg [7:0] tmp_data;

    always @ (posedge clk)
    begin
        rx_r1 <= {rx_r1[0], rx};
    end

    always @ (posedge clk) 
    begin
        rx_r2 <= {rx_r2[0], rx_r1[1]};
    end

    always @ (posedge clk or posedge rst) 
    begin
        if (rst) 
            rxd_en <= 1'd0;
        else 
        begin
            if (rx_r2 == 2'b10) 
                rxd_en <= 1'd1;
            else if ((bit_cnt == 4'd9) && (baud_cnt == B_CNT / 2)) 
                rxd_en <= 1'd0;
            else 
                rxd_en <= rxd_en;
        end
    end

    always @ (posedge clk or posedge rst) 
    begin
        if (rst)
            baud_cnt <= 16'd0;
        else if (rxd_en) 
        begin
            if (baud_cnt == B_CNT - 1) 
                baud_cnt <= 16'd0;
            else 
                baud_cnt <= baud_cnt + 1'b1;
        end
        else 
            baud_cnt <= 16'd0; 
    end

    always @ (posedge clk or posedge rst)  
    begin
        if (rst) 
            bit_cnt <= 4'd0;
        else if (rxd_en) 
        begin
            if (baud_cnt == B_CNT - 1) 
                bit_cnt <= bit_cnt + 1'b1;
            else 
                bit_cnt <= bit_cnt;
        end
        else 
            bit_cnt <= 4'd0;
    end

    always @ (posedge clk or posedge rst) 
    begin
        if (rst)
            tmp_data <= 8'b0;
        else if (rxd_en) 
        begin
            if (baud_cnt == B_CNT / 2) 
            begin
                case (bit_cnt) 
                    4'd1: tmp_data[0] <= rx_r2[1];
                    4'd2: tmp_data[1] <= rx_r2[1];
                    4'd3: tmp_data[2] <= rx_r2[1];
                    4'd4: tmp_data[3] <= rx_r2[1];
                    4'd5: tmp_data[4] <= rx_r2[1];
                    4'd6: tmp_data[5] <= rx_r2[1];
                    4'd7: tmp_data[6] <= rx_r2[1];
                    4'd8: tmp_data[7] <= rx_r2[1];
                    default: ;
                endcase
            end
            else 
                tmp_data <= tmp_data;
        end    
        else 
            tmp_data <= 8'b0;
    end

    always @ (posedge clk or posedge rst) 
    begin
        if (rst)
            rx_data <= 8'b0;
        else if (bit_cnt == 4'd9) 
            rx_data <= tmp_data;
        else 
            rx_data <= 8'b0;
    end

    always @ (posedge clk or posedge rst) 
    begin
        if (rst)
            rx_done <= 1'b0;
        else if (bit_cnt == 4'd9) 
            rx_done <= 1'b1;
        else 
            rx_done <= 1'b0;
    end

endmodule